#include<linux/fs.h>
#include<linux/uaccess.h>  
#include<asm/io.h> 
#include<linux/device.h>   
#include <linux/module.h>




unsigned int major;
static struct class *led_class;

/*IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 : Address: 229_0000h base + 14h offset = 229_0014h*/
static volatile unsigned int *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3;

/*GPIOx_GDIR:Address: 020A_C000 + 4h offset */
static volatile unsigned int *GPIO5_GDIR;


/*GPIOx_DR:Address: 020A_C000 + 0h offset */
static volatile unsigned int *GPIO5_DR;

int led_drv_open(struct inode *inode, struct file *file)
{
	/* 使能GPIO5 */
	//GPIO5默认使能，无需设置
	
	/* 配置GPIO5_3为GPIO，MUX_MODE：101 */
	*IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 &= ~0xf;   //清除
	*IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 |= 0x5;
	
	/* 配置GPIO5_3为OUTPUT,1 */
	*GPIO5_GDIR |= (1<<3);
	
	return 0;
}


static ssize_t led_drv_write(struct file *file, const char __user *user_buf, size_t count,loff_t *ppos)
{
    char val;
	int ret;
	
    ret = copy_from_user(&val, user_buf,1);
	
    /* 根据user_buf 设置引脚状态 */
    if(val)
	{
	   *GPIO5_DR &= ~(1<<3);//低电平，打开LED
	}
	else
	{
	   *GPIO5_DR |= (1<<3);
	}
	return 0;
}


static const struct file_operations led_drv_fops = {
    .owner = THIS_MODULE,
	.open  = led_drv_open,
	.write = led_drv_write,
};
	
static int __init led_drv_init(void)
{
	printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
	
    /* 注册字符设备 */
    major = register_chrdev(0, "myled", &led_drv_fops);
	
    /* 地址映射 */
	//驱动不能直接访问硬件，所以要将物理地址转化为虚拟地址
	 IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = ioremap (0x2290014, 4);
	 GPIO5_GDIR = ioremap (0x020AC004, 4);
	 GPIO5_DR = ioremap (0x020AC000, 4);
	 
    /* 创建一个设备节点 */
	led_class = class_create(THIS_MODULE, "myled"); 
	device_create(led_class, NULL, MKDEV(major, 0), NULL, "myled"); // dev/myled 
	
	return 0;
}
static void __exit led_drv_exit(void)
{
   /* 删除设备节点 */
	  device_destroy(led_class,  MKDEV(major, 0));
	  class_destroy(led_class);

   /* 注销字符设备 */
   unregister_chrdev(major, "myled");
   
   /* 取消地址映射 */
   iounmap (IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3);
   iounmap (GPIO5_GDIR);
   iounmap (GPIO5_DR);
   
}

module_init(led_drv_init);
module_exit(led_drv_exit);
MODULE_LICENSE("GPL");



